
//Importamos librerias de Java
import java.io.IOException;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Leo, kike , yoas y fernando
 */
//INICIAMOS EL CODIGO SINTACTICO
public class Sintactico {
    // creamos dos arreglos para manejar errores y métodos de java manejados
    String err="",metodos=""; 
    //Cramos una variable de tipo yylex Analizador Léxico para ser el análisis 
    //sintáctico
    public Yylex analizadorLexico;
    //Variables finales 
    //para indicar sobre que producciones de la grámatica entran nuestras expresiones del archivo
    final int ENTERO = 1;
    final int FLOTANTE = 2;
    final int INT_FLOAT = 3;
    final int ID = 4;
    final int MAS = 5;
    final int MENOS = 6;
    final int DIV = 8;
    final int MUL = 7;
    final int PTOYCOMA = 9;
    final int COMA = 10;
    final int LPAR = 11;
    final int RPAR = 12;

    //Variable auxiliar para indicar la aceptación de un indentificiador o numero, etc.
    boolean acepta=true;
    
    //Toke null, para finalizar el archivo, asi como token actual para mandar a llamar otro y comparar
    //el actual
    public static Token tokenAnterior = null;
    public static Token tokenActual;
    public static ListaLigadaDoble tablaSimbolos; //Tabla de simbolos para nuestros Analizado le´xico sintáctico
    
    //Sobrecargamos método Sintactico
    //esta método trabajara con un analizador léxico ya creado así como su tabla de simbolos
    public Sintactico(Yylex analizadorLexico, ListaLigadaDoble tablaSimbolos) {
        this.analizadorLexico = analizadorLexico;
        this.tablaSimbolos = tablaSimbolos;
    }

    //Definición del método programa; que define lo que contiene un programa en general 
    public void program() {
        metodos+="PROGRAM\n"; //si se accede a esta función indicamos el uso de esta función
        decl(); //Primera Derivación para saber si es una declaración 
        sent(); //Segunda Derivación finalizar indentificadores
        //System.out.println("Acepta Programa");
    }

    //Definición del método delc para declaraciones como son asignación de variables, etc.
    public void decl() {
        metodos+="DECL\n"; //si se accede a esta función indicamos el uso de esta función
        tipo(); //Primera Derivación para saber si es una declaración para llevarnos al tipo
        var(); //Segunda Declarión para el nombre de la variable
        consumir(PTOYCOMA); //Todas las variables tiene que tener punto y coma para finalizar asignación
        //System.out.println("Acepta DECL");
        delcp(); //Si hay declaraciones contiguas una de la otra
    }

    //Definición del método delcp para las declaraciones en un renglón de dos o más variables
    public void delcp() {
        metodos+="DECLP\n";//si se accede a esta función indicamos el uso de esta función
        if(tokenActual.tipo == INT_FLOAT){ //Si el token que se recibe indica un tipo nos vamos a tipo
            tipo(); //Buscamos tipo de variable
            var(); // Nombre de varibles 
            consumir(PTOYCOMA);//Todas las variables tiene que tener punto y coma para finalizar asignación
            //System.out.println("Acepta DECL");
            delcp(); //De manera ciclica lo haremos 
        }else{
            //System.out.println("Acepta el siguiente token es:"+tokenActual);
            //Si no sige un tipo de lo contrario no se hará nada, solo retornan a nuestra función orginal
        }
    }
    
    //Definimos el metodo sent para analizar las expresiones conocidad en la grámatica
    public void sent(){
        metodos+="SENT\n";//si se accede a esta función indicamos el uso de esta función
        exp(); //Buscamos que tipo de expresión hacemos referencia
        consumir(PTOYCOMA); //Toda expresión debe terminar con punto y coma
        sentp();//Buscamos si hay mas expresiones contiguas
    }

    //Definiimos el metodo para buscar expresiones en un mismo renglón declaradas de forma contigua
    public void sentp(){
        metodos+="SENTP\n";//si se accede a esta función indicamos el uso de esta función
        /*Haremos una selección precisa de cada elemento de los cuales tiene que cumplir para 
        considerarse como una expresión empezando con el tipo */
        if(tokenActual.tipo == FLOTANTE || tokenActual.tipo == ENTERO || tokenActual.tipo == ID
                || tokenActual.tipo == MAS || tokenActual.tipo == MENOS || tokenActual.tipo == LPAR){
            exp(); //Buscamos si hay más expresiones
            consumir(PTOYCOMA); //Toda expresión debe terminar con punto y coma
            sentp(); //Ciclamos hasta que no se encuentren expresiones 
        }else{
            //System.out.println("Acepta el siguiente token es:"+tokenActual);
            //Si no sige una de las expresiones no se hará nada, solo retornan a nuestra función orginal
        }
    }
    //Definimos el método para saber de que tipo de varibale se trata
    public void tipo() {
        metodos+="TIPO\n";//si se accede a esta función indicamos el uso de esta función
        //Hacemos un pequeño switch para evaluar nuestro tipo
        switch (tokenActual.tipo) {
            case INT_FLOAT: //si es entero o flotante
                avanzar(); //leemos el siguiente y invocamos nuestro método avanzar
                break; //regresamos por que ya sabemos de que tipo se trata
            default: //de cualquiier forma sera un error
                error(); //invocamos nuestra función error
                break; //salimos
        }
    }

     //Definimos nuestro método para indetificadores ya con un nombre
    public void var() {
        metodos+="VAR\n";//si se accede a esta función indicamos el uso de esta función
        consumir(ID); //Leemos el nuevo indentificador
        varp(); //si hay mas nombres de variables de un tipo accedemos a este método
    }
    //Definimos nuestro  método para declraciones de variables de uno o más nombres
    public void varp() {
        metodos+="VARP\n"; //si se accede a esta función indicamos el uso de esta función
        if (tokenActual.tipo == COMA) {  //FIRST COMA
            avanzar(); //invocamos método avanzar para leer siguiente token
            consumir(ID); //Guardamos el identidicador 
            varp(); //Ciclamos 
        }else { //No fue COMA y por lo tanto termina
            //System.out.println("Acepta el siguiente token es:"+tokenActual);
        }
    }

    //Declaración del método para expresiones de forma generaal
    public void exp() {
        metodos+="EXP\n";//invocamos método avanzar para leer siguiente token
        term(); //Si se trata de un termino llamamos nuestro método que nos ayudará a saber que tipo de termino es
        expp(); //mas expresiones contiguas entre sí
    }

    //SI hay expresiones contiguas ejemplo 2,2,2,1; etc
    public void expp() {
        metodos+="EXPP\n";//invocamos método avanzar para leer siguiente token
        //Trabajamos con los first de esta función  y procedmos a leer
        if(tokenActual.tipo == MAS || tokenActual.tipo == MENOS){
            avanzar(); // Leemos el siguiente token
            term(); //Una vez vemos el termino de que se trata
            expp(); //ciclamos
        }else{
            //System.out.println("Acepta el siguiente token es:"+tokenActual);
            //Si no sige una de las expresiones no se hará nada, solo retornan a nuestra función orginal
        }
        
    }
    //Definimos método para términos de nestras exprsiones en el archivo
    public void term() {
        metodos+="TERM\n";//invocamos método avanzar para leer siguiente token
        factor(); //Se trata de un factor o sino de 
        termp(); //términos seguidos en la misma linea;
    }

    //Definimos los n terminos que tengamos en unas declaraciones
    public void termp() {
        metodos+="TERMP\n";//invocamos método avanzar para leer siguiente token
        //First de temp debe ser un signo * o /
        if(tokenActual.tipo == MUL || tokenActual.tipo == DIV){
            avanzar(); //avanzamos y leemos el siguiente token
            factor(); //si sigue un factor invocamos nuevo método
            termp(); //ciclamos
        }else{
           // System.out.println("Acepta el siguiente token es:"+tokenActual);
            //Si no sige una de las expresiones no se hará nada, solo retornan a nuestra función orginal
        }
    }
    
    //Definimos el método factor para hacer caso por caso de lo que determina nuestras expresiones
    public void factor() {
        metodos+="FACTOR\n";//invocamos método avanzar para leer siguiente token
        //Inicamos los first de para tipo en un case en sus variables finales
        switch (tokenActual.tipo) {
            case ID:
                avanzar();
                break;
            case ENTERO:
                avanzar();
                break;
            case FLOTANTE:
                avanzar();
                break;
            case LPAR:
                avanzar();
                exp();
                consumir(RPAR);
                break;
            default:
                error();
                break;
        }
    }

    //Función importante para ignorar caracteres especiales como ;  EN DECLARACIONES
    //recibe un entero
    public void consumir(int i) { //Comparar todo menos operadores
        metodos+="CONSUMIR\n"; //invocamos método avanzar para leer siguiente token
        if (tokenActual.tipo == i) { // Si nuestro tipo es igual al entero que recibimos 
            avanzar(); //avanzamos
            //if(tokenActual == null)
              //  error();
        } else {
            error(); // si no fue un error sintáctico
        }
    }
    /*
    public void consumir(int i, String s) { //Comparar todo operadores
        if (tokenActual.tipo == i && tokenActual.lexema.equals(s)) {
            avanzar();
        } else {
            error();
        }
    }
    */
    
    //Función para leer token como van llegando de esta forma será más fácil recorrer nuestro archivo
    public void avanzar(){
        metodos+="AVANZAR\n"; //invocamos método avanzar para leer siguiente token
        try { //intentaremos :
            if(tokenActual != null){ //comparar si nuestro final de archivo a llegado
                    //v.add(tokenAux.lexema);
                    if(tokenActual.tipo == 3 || tokenActual.tipo == 4){
                        tablaSimbolos.insertar(tokenActual);    // si son PR o ID insertamos en nuestra tabla de simbolos
                    }
            }
            tokenAnterior = tokenActual; //Asigamos nuevos tokens
            tokenActual = this.analizadorLexico.getSigToken(); //Asigamosa nuestra nueva variable so valor del siguiente token

            if(tokenActual == null) tokenActual= new Token("", 0); // si es nulo el siguiente token entonces no se pone 
            //nada como token  

        } catch (IOException ex) {
            ex.printStackTrace(); //atrapamos exepeción 
        }
    }
//Finalmente el error, función importante
   public void error(){
       System.out.println("ERROR SINTACTICO en:"+tokenAnterior.lexema); // se muestra el error 
       System.out.println("En la linea:"+(this.analizadorLexico.yyline+1)); //El numero de la linea donde esta el error
       err+="ERROR SINTACTICO en la linea: "+(this.analizadorLexico.yyline+1)+" por: "+tokenAnterior.lexema+"\n";
       //arreglo error para despues ser enviado a nuestro text area de errores
       acepta=false; //si hubo errores el programa no se puede seguir compilando 
   }

   
}
